# -*- shell-script -*-

# 37device_dt - Hardware database scanning routines and variables for
#               systems with device-tree, with or without ibm,vpd properties.

# This file is part of the Linux lsvpd package.

# (C) Copyright IBM Corp. 2002, 2003, 2004, 2005

# Maintained by Martin Schwenke <martins@au.ibm.com>

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    
# $Id: 37device_dt,v 1.1 2006/04/11 18:38:28 emunson Exp $

[ -n "$source_device_tree" ] || return 0

# Note, to avoid creating another module, there's another exit
# condition below relating to sysfs.

######################################################################

make_multiplexed get_source_node_device

get_source_node_device_DEFAULT ()
{
    # Sets: source_node
    source_node=""

    local node_type="$1"
    local bus_info="$2"
    local subtype="$3"

    local bus_alias
    bus_alias_get "$bus_info" "device-tree"
    source_node="$bus_alias"

    [ -n "$source_node" ] && return 0 ### !!!

    local bus_type="${bus_info%/*}"
    local bus_addr="${bus_info#*/}"

    local parent_node
    get_parent_node "device" "$bus_type" "$bus_addr"
    [ -n "$parent_node" ] || return 1  ### !!!

    local dt_type
    case "${node_type}:${subtype}" in
	(scsi:enclosure) dt_type="Enclosure" ;;
	(raid:enclosure) dt_type="Enclosure" ;;
	(ide:cdrom)      dt_type="disk"      ;;
	(ata:cdrom)      dt_type="disk"      ;;
	(sata:cdrom)     dt_type="disk"      ;;
	(*:*)            dt_type="$subtype"  ;;
    esac

    local bus id subid
    dt_parse_address "$bus_type" "$bus_addr"

    source_node="${source_device_tree}${parent_node#${db_bus_dt_dir}}"

    local t=$(dec2hex "$id")
    source_node="${source_node}/${dt_type}@${t}"
    if [ -n "$subid" ] && [ "$subid" -ne 0 ] ; then
	t=$(dec2hex "$subid")
	source_node="${source_node},${t}"
    fi

    bus_alias_set "$bus_info" "$source_node" "device-tree"
}

######################################################################

make_multiplexed dt_parse_address

dt_parse_address_scsi ()
{
    # Sets: bus, id, subid

    local bus_addr="$1"
    
    local host target lun
    scsi_parse_addr_hook "$bus_addr"

    id="$target"
    subid="$lun"
}

dt_parse_address_ide ()
{
    # Sets: bus, id, subid

    local bus_addr="$1"

    # FIXME: This should work in most cases.
    bus="${bus_addr%.*}"
    id=$(( $bus % 2 * 2 + ${bus_addr#*.} ))
    subid=""
}

######################################################################

[ -n "$sysfs_dir" ] || return 0

get_source_node_device_usb ()
{
    # Sets: source_node
    source_node=""

    local bus_info="$1"
    local subtype="$2"

    local bus_alias
    bus_alias_get "$bus_info" "device-tree"
    source_node="$bus_alias"

    [ -n "$source_node" ] && return 0 ### !!!

    local bus_type="${bus_info%/*}"
    local bus_addr="${bus_info#*/}"

    local parent_node
    get_parent_node "device" "$bus_type" "$bus_addr"
    [ -n "$parent_node" ] || return 1  ### !!!

    local sysfs_device_node
    get_sysfs_device_node "$bus_type" "$bus_addr"
    [ -n "$sysfs_device_node" ] || return 1

    local usb_name suffix config interface
    usb_name="${sysfs_device_node%%/host*}"
    usb_name="${usb_name##*/}"  # basename
    suffix="${usb_name%%*:}"
    config="${usb_name%.*}"
    interface="${usb_name#*.}"

    # Include root hub.
    source_node="${source_device_tree}${parent_node#${db_bus_dt_dir}}/hub@1"

    local ports="${usb_name%%:*}"
    ports="${ports#*-}"

    # Hub port numbers are separated by '.', so need to process
    # intermediate hubs.
    while [ "$ports" != "${ports%%.*}" ] ; do
	source_node="${source_node}/hub@${ports%%.*}"
	ports="${ports#*.}"
    done

    local f="${sysfs_device_node}/../bNumInterfaces"
    local num_interfaces
    [ -f "$f" ] && read num_interfaces <"$f"
    [ -n "$num_interfaces" ] || num_interfaces=1

    if [ "$num_interfaces" = "1" ] ; then
	source_node="${source_node}/${subtype}@${ports}"
    else
	# 2 lines to fit into 80 columns - no other reason  :-)
	# FIXME: It seems to make no sense have interface before
	# config, but the only example I've seen (a keyboard with a
	# second interface) seems to match this.
	source_node="${source_node}/device@${ports}"
	source_node="${source_node}/${subtype}@${interface},${config}"
    fi

    bus_alias_set "$bus_info" "$source_node" "device-tree"
}
